<template>
  <div :class="`comp-ref-config-wrapper visualComponents_theme_${componentStyle}`">
    <el-tooltip
      ref="preTip"
      placement="left"
      :effect="xvueTheme"
      :popper-class="`visualComponents_theme_${componentStyle} comp-ref-config-wrapper-tooltip`"
      :trigger-keys="[]"
    >
      <xvue-comp-ref-config
        v-if="isReady"
        ref="compRefConfig"
        v-model="curValue"
        class="comp-ref-config"
        :editorHeight="codeMirrorHeight"
        :placeHolder="placeholder"
        :methodSelect="true"
      />
      <template #content>
        <div class="previewVal">
          <pre>{{ previewVal }}</pre>
        </div>
      </template>
    </el-tooltip>
    <slot name="rightInner"></slot>
  </div>
</template>
<script>
import { getLowCodeExpVal } from '@/components/common/low-code/low-code-util.js';
import { bindVisibleChange, isArray, isNum, isObject, toString } from '@/utils/util.js';
import { nextTick } from 'vue';
export default {
  components: {},
  props: {
    value: [String, Number],
    codeMirrorHeight: {
      type: String,
      default: '30',
    },
    placeholder: {
      type: String,
      default: '',
    },
    componentStyle: {
      type: String,
      default: window._adoPremise.uc.theme || 'light',
    },
  },
  emits: ['update:value', 'mounted'],
  data() {
    return {
      curValue: toString(this.value),
      timer: null,
      isReady: true,
      xvueTheme: window._adoPremise.uc.theme || 'light',
    };
  },
  computed: {
    previewVal() {
      const value = toString(this.value);
      if (value.includes('(')) {
        return value;
      }
      if (value.includes('=') && !value.includes('==')) {
        return value;
      }

      let val = getLowCodeExpVal({ expression: value });

      const type = typeof val;
      const simpleTypes = ['string', 'undefined', 'boolean', 'number'];
      if (simpleTypes.includes(type)) {
        return val;
      } else if (value.startsWith('{{Global'.toLowerCase())) {
        if (isObject(val)) {
          val = { ...val };
          Object.entries(val).map(([i, n]) => {
            if (isObject(n) || isArray(n)) {
              delete val[i];
            }
          });
        }
        return val;
      } else if (val === null) {
        return null;
      } else {
        if (val.$data) {
          val = { ...val.$data };
          delete val.chart;
          val = JSON.parse(JSON.stringify(val));

          const arr = [
            'dfCssStyle', 'actionUnwatchs', 'asTooltipFilter', 'asTooltipWatcher', 'apiCacheKey', 'expressionWatchs',
            'isVisualVappShowLoa', 'fontStyle', 'componentStyleClass', 'lastConfigLinkage',
            'isFirstChangeWidget', 'pageStatus', 'hasWatchEmitCompone', 'isFirstSend', 'historyTimer',
            'timers', 'chartIsCreated', 'xvueMutationObserve', 'receivedEvents', 'curComp',
            'extStylesTimer', 'clickLock', 'isLoading', 'tablePage', 'orgConfig', 'style', 'isFirstRequest',
            'headerStyle', 'contentStyle', 'footerStyle', 'contentExtraStyle',
          ];
          arr.forEach(k => {
            delete val[k];
          });
          Object.entries(val).map(([key, n]) => {
            if (isArray(n)) {
              val[key] = ['...'];
            } else if (isObject(n)) {
              val[key] = { '...': '...' };
            } else {}
          });
        }
        try {
          val = JSON.stringify(val, null, 2);
        } catch ( err) {
          val = null;
        }
        return val;
      }
    },
  },
  watch: {
    value(val) {
      this.curValue = toString(val);
    },
    curValue(val) {
      clearTimeout(this.timer);
      this.timer = setTimeout(() => {
        let _val = val;
        if (typeof this.value === 'number' && isNum(_val)) {
          _val = Number(_val);
        }
        this.$emit('update:value', _val);
        const editorVm = this.$refs?.compRefConfig;
        if (editorVm && editorVm.editor.getValue() !== val) {
          editorVm.editor.setValue(val);
        }
      }, 300);
    },
    placeholder() {
      this.isReady = false;
      nextTick(() => {
        this.isReady = true;
      });
    },
    previewVal() {
      this.$refs.preTip.updatePopper();
    },
  },
  created() {},
  mounted() {
    bindVisibleChange(this.$el, () => {
      this.$refs.compRefConfig.editor.refresh();
    });
    this.$emit('mounted', true);
  },
  beforeUnmount() {
    clearTimeout(this.timer);
  },
  methods: {},
};
</script>
<style lang="less" scoped>
.comp-ref-config-wrapper{
  width: 100%;
  position: relative;
  font-size: 12px;
  :deep(.comp-ref-config){
    width: 100%;
    height: 100%;
    .CodeMirror{
      height: 100%;
      .CodeMirror-lines{
        margin-top: 3px;
      }
    }
  }
}
.comp-ref-config-wrapper.visualComponents_theme_dark{
  :deep(.comp-ref-config){
    .CodeMirror{
      background-color: #0d263a;
      color: #98cae6;
      border: 1px solid #116584;
      .CodeMirror-cursor{
        border-left: 1px solid #98cae6;
      }
      .cm-variable{
        color: #98cae6;
      }
      .cm-number{
        color: #f56c6c;
      }
      .cm-operator{
        color: #00f0ff;
      }
      .cm-property{
        color: #98cae6;
      }
    }
  }
}
.comp-ref-config-wrapper.visualComponents_theme_real{
  :deep(.comp-ref-config){
    .CodeMirror{
      background-color: #191919;;
      color: #eee;
      border: 1px solid #676767;
      .CodeMirror-cursor{
        border-left: 1px solid #fff;
      }
      .cm-variable{
        color: #eee;
      }
      .cm-number{
        color: #eee;
      }
      .cm-operator{
        color: #00f0ff;
      }
      .cm-property{
        color: #98cae6;
      }
    }
  }
}

</style>
<style lang="less">
.comp-ref-config-wrapper-tooltip{
  .previewVal{
    pre{
      max-width: 400px;
      max-height: 600px;
      overflow-y: overlay;
      font-size: 12px;
      color: #629508;
      line-height: 12px;
      min-width: 20px;
      min-height: 20px;
    }
  }
}
.visualComponents{
  .CodeMirror-hints{
    z-index: 10000; // 防止别的弹窗挡住下拉列表
  }
}
</style>
